package com.mg.plugin.agrometeorology.common;

import com.mg.model.Model;
import com.mg.plugin.agrometeorology.entity.StationData;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 温度计算
 */
public class TemperatureCalculator {

    /**
     * 计算站平均温度，（最高温+最低温）/2
     *
     * @return 平均温度
     */
    private static float calcStationAvgTemperature(StationData stationData) {
        return (stationData.getMaxTemp() + stationData.getMinTemp()) / 2.0f;
    }

    /**
     * 全省日平均温度计算
     *
     * @param stationAvgTemps 站点温度
     * @param model
     * @return 省平均温度
     */
    private static float calcAvgTemperature(List<StationData> stationAvgTemps, Model model) {
        if (stationAvgTemps == null || stationAvgTemps.size() == 0) {
            return 0;
        }
        float totalTemp = 0;
        int avgLess = 0;
        for (StationData stationData : stationAvgTemps) {
            float avgTemp = calcStationAvgTemperature(stationData);
            if (avgTemp < 0) {
                avgLess++;
            } else {
                totalTemp += avgTemp;
            }

        }
        //model.OutputLog(Model.LogLevel.Info, "calcAvgTemperature:Date=" + stationAvgTemps.get(0).getDate() + "totalTemp=" + totalTemp + "stationAvgTempSize=" + stationAvgTemps.size() + "avgLess" + avgLess);
        return totalTemp / (stationAvgTemps.size() - avgLess);
    }

    /**
     * 全省平均积温计算
     *
     * @return 全省平均积温
     */
    public static float calcAccumulatedTemperature(Map<String, List<StationData>> stationDataList, int i, Model model) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        float accTemp = 0;
        int count = 0;
        float temp;
        float avgTemp = 0;
        for (String date : stationDataList.keySet()) {
            Date calcDate = DateCalculator.calcTime(sdf.parse(date), i);
            if (calcDate.before(sdf.parse(date))) {
                continue;
            }
            count++;
            List<StationData> data = stationDataList.get(date);
            temp = calcAvgTemperature(data, model);
            if (!String.valueOf(temp).equals("NaN")) {
                avgTemp = temp;
            }
//            model.OutputLog(Model.LogLevel.Info, "calcAccumulatedTemperature:accTemp=" + accTemp + "avgTemp" + avgTemp);
            accTemp += avgTemp;
        }
//        model.OutputLog(Model.LogLevel.Info, "calcAccumulatedTemperature:accTemp=" + accTemp + "count" + count);
        return accTemp;
    }

    /**
     * 全省旬平均温度
     *
     * @param stationDataList
     * @param i
     * @param model
     * @return
     */
    public static float calcTendaysAverageTemperature(Map<String, List<StationData>> stationDataList, int i, Model model) throws ParseException {
        if (i % 2 == 1) {
            return 999999.9f;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        float accTemp = 0;
        int count = 0;
        float temp;
        float avgTemp = 0;
        for (String date : stationDataList.keySet()) {
            Date calcDate = DateCalculator.calcTime(sdf.parse(date), i);
            Date beforeDate = DateCalculator.calcTendaysBeforeTime(sdf.parse(date), i);
            if (calcDate.before(sdf.parse(date)) || beforeDate.after(sdf.parse(date))) {
                continue;
            }
            count++;
            List<StationData> data = stationDataList.get(date);
            temp = calcAvgTemperature(data, model);
            if (!String.valueOf(temp).equals("NaN")) {
                avgTemp = temp;
            }
//            model.OutputLog(Model.LogLevel.Info, "calcAccumulatedTemperature:accTemp=" + accTemp + "avgTemp" + avgTemp);
            accTemp += avgTemp;
        }
//        model.OutputLog(Model.LogLevel.Info, "calcAccumulatedTemperature:accTemp=" + accTemp + "count" + count);
        return count > 0 ? accTemp / count : accTemp;
    }

    /**
     * 全省旬平均温度
     *
     * @param stationDataList
     * @param i
     * @param b
     * @param model
     * @return
     */
    public static float calcTendaysTemperatureSuitability(Map<String, List<StationData>> stationDataList, int i, boolean b, Model model) throws ParseException {
        if (i % 2 == 1) {
            return 999999.9f;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        float accTemp = 0;
        int count = 0;
        double temp;
        double avgTemp = 0;
        Calendar calendar = Calendar.getInstance();
        for (String date : stationDataList.keySet()) {
            Date calcDate = DateCalculator.calcTime(sdf.parse(date), i);
            Date beforeDate = DateCalculator.calcTendaysBeforeTime(sdf.parse(date), i);
            if (calcDate.before(sdf.parse(date)) || beforeDate.after(sdf.parse(date))) {
                continue;
            }
            count++;
            List<StationData> data = stationDataList.get(date);
            calendar.setTime(calcDate);
            temp = calcTemperatureSuitability(data, model, calendar, b);
            if (!String.valueOf(temp).equals("NaN")) {
                avgTemp = temp;
            }
//            model.OutputLog(Model.LogLevel.Info, "calcAccumulatedTemperature:accTemp=" + accTemp + "avgTemp" + avgTemp);
            accTemp += avgTemp;
        }
//        model.OutputLog(Model.LogLevel.Info, "calcAccumulatedTemperature:accTemp=" + accTemp + "count" + count);
        return count > 0 ? accTemp / count : accTemp;
    }

    private static double calcTemperatureSuitability(List<StationData> data, Model model, Calendar date, boolean isRice) {
        double suitTemp = 0;
        int month = date.get(Calendar.MONTH) + 1;
        int day = date.get(Calendar.DAY_OF_MONTH);
        double[] var = TemperatureData.getVar(month, day, isRice);
        double b = (var[1] - var[2]) / (var[2] - var[0]);
        int count = 0;
        for (StationData stationData : data) {
            float avgTemp = calcStationAvgTemperature(stationData);
            double da = calcSuitabilityTemperature(avgTemp, var, b, model);
            if (da != 999999.99) {
                suitTemp += da;
                count++;
            }
        }
        return count > 0 ? suitTemp / count : suitTemp;
    }

    private static double calcSuitabilityTemperature(float avgTemp, double[] var, double b, Model model) {
        double res = (avgTemp - var[0]) * Math.pow(var[1] - avgTemp, b)
                / ((var[2] - avgTemp) * (var[1] - var[2]));
        if (Double.isInfinite(res)) {
            model.OutputLog(Model.LogLevel.Info, "avgTemp:" + avgTemp + "var[0]:" + var[0]
                    + "var[1]:" + var[1] + "var[2]:" + var[2] + "b:" + b);
            return 999999.99;
        }
        return res;
    }

    public static void main(String[] args) {
        double b = (32 - 25) / (32 - 13);
        System.out.print(Math.pow(0.63 * 1.0 * -0.04, (1 / 3.0)));
        System.out.print(0.63 * 1.0 * -0.04);
    }

}
